<template>
    <div class="sku-table">
        <table border class="sku-table-body">
            <tr class="sku-table-header">
                <th
                v-for="(item, colIndex) in specs"
                :key="colIndex"
                class="sku-table-header-cell"
                >
                <el-select
                    v-if="filterable"
                    v-model="headerFilterParams[item.name]"
                    :placeholder="item.name"
                    clearable
                    style="width: 100%"
                    @change="
                    (value) => {
                        onSltChange(value, item.name);
                    }
                    "
                >
                    <el-option label="全部" value=""></el-option>
                    <el-option
                    v-for="(child, index2) in item.values"
                    :key="index2"
                    :label="child.name"
                    :value="child.name"
                    ></el-option>
                </el-select>
                <span v-else class="spec-name">
                    {{ item.name }}
                </span>
                </th>
                <th
                v-for="(item, colIndex) in skuProperties"
                :key="colIndex + specs.length + 1"
                class="sku-table-header-cell"
                >
                <span v-if="item.readOnly">{{ item.name }}</span>
                <el-input
                    v-else
                    v-model="skuPropertiesValue[item.id]"
                    @update:modelValue="
                    (value) => {
                        checkValue(value, item);
                    }
                    "
                    @keyup.enter="
                    () => {
                        onBulkEdit(item.id);
                    }
                    "
                    :placeholder="item.name"
                />
                </th>
            </tr>
            <tr v-for="(row, rowIndex) in renderTableRows" :key="row.id">
                <td
                    class="sku-table-body-cell"
                    v-for="(child, colIndex) in row.columns"
                    :class="[
                        child.shouldSetRowSpan ? '' : 'hide',
                        rowIndex === rowLastCanSpan[colIndex] ? 'col-last-rowspan' : '',
                        colIndex < specs.length - 1 ? 'row-span-style' : '',
                    ]"
                    :rowspan="child.shouldSetRowSpan ? assignRule[colIndex] : ''"
                    :key="colIndex"
                >
                    <span>{{ child.showValue }}</span>
                </td>
                <td
                    v-for="(child, colIndex) in skuProperties"
                    :key="colIndex + skuProperties.length + 1"
                    class="sku-table-body-cell"
                    >
                    <el-select 
                        v-if="child.type == 'currency'" 
                        v-model="row[child.id]" 
                        class="m-2 no-border-input" 
                        placeholder=" "
                        @update:modelValue="
                        (value) => {
                            checkValue(value, child, row);
                        }
                        "
                    >
                        <el-option :label="t('美元')" value="usd" />
                        <el-option :label="t('人民币')" value="cny" />
                        <el-option :label="t('韩元')" value="krw" />
                    </el-select>
                    <el-input
                        v-if="child.type == 'text'"
                        v-model="row[child.id]"
                        @update:modelValue="
                        (value) => {
                            checkValue(value, child, row);
                        }
                        "
                        class="no-border-input"
                    />
                </td>
            </tr>
        </table>
    </div>
</template>
  
<script setup lang="ts">
import { ref, onMounted, computed, watch, unref } from "vue";
// import { v4 as uuidv4 } from "uuid";
import { uuid } from '/@/utils/random'

import { useI18n } from 'vue-i18n'
const { t } = useI18n()
  
interface modelValue {
    sku_ids: Array<string>;
    sku_names: Array<string>;
    [x: string]: any;
}
  
  interface specValue {
    id: string;
    name: string;
  }
  
  interface spec {
    id: string;
    name: string;
    values: Array<specValue>;
  }
  
  type propertyDefaultValueFn = (rowIndex: number, columns: Array) => string;
  
interface property {
    id: string;
    name: string;
    readOnly: boolean;
    pattern: RegExp;
    defaultValue: string | propertyDefaultValueFn;
    format: (row: any) => any;
}
  
const Props = withDefaults(
    defineProps<{
      modelValue: Array<modelValue>;
      specs: Array<spec>;
      skuProperties: Array<property>;
      filterable: boolean;
      keepWhenSpecChange: boolean; //规格改变时是否保留已有数据
    }>(),
    {
        modelValue: [],
        specs: [],
        skuProperties: [],
        filterable: true,
        keepWhenSpecChange: false,
    }
);
  
const emit = defineEmits(["update:modelValue"]);
  
let headerFilterParams = ref({});
let skuPropertiesValue = ref({});
let originTableRows = ref([]);
let renderTableRows = ref([]);
  
let specsValues = computed(() => {
    return unref(Props.specs);
});
let propertiesValues = computed(() => {
    return unref(Props.skuProperties);
});
let hasFilter = computed(() => {
    //是否有筛选条件
    return Object.values(headerFilterParams.value).filter((t) => !!t).length > 0;
});
  
let renderSpecs = computed(() => {
    //最终渲染出来的规格数量数组，比如3*3*3，如果有过滤条件则被认为是1如3*3*1
    return specsValues.value
        .map((t) => t.values.length)
        .map((t, index) => {
            return hasFilter.value
                ? headerFilterParams.value[specsValues.value[index].name]
                    ? 1
                    : t
                : t;
        });
});
  
  let skuTotal = computed(() => {
    // 渲染的sku总数
    return renderSpecs.value.reduce(
      (result, item) => result * item,
      renderSpecs.value.length ? 1 : 0
    );
  });
  
  let assignRule = computed(() => {
    //合并单元格规则数组，[6,2,1]表示第一例按6行合并，第二列按2行合并
    return renderSpecs.value.reduce((result, item, index) => {
      let preValue = result[index - 1];
      if (preValue) {
        result.push(preValue / item);
      } else {
        result.push(skuTotal.value / item);
      }
      return result;
    }, []);
  });
  
  let rowLastCanSpan = computed(() => {
    let indexArr = Array.from(new Array(skuTotal.value).keys()); //生成行的索引数组
    //每列可以合并的最后一行的行索引数组，为了设置样式
    return assignRule.value.map((t, index, array) => {
      return index === array.length - 1
        ? null
        : indexArr.filter((row) => row % t === 0).pop();
    });
  });
  
onMounted(render);
  
watch(() => [...Props.specs], render, {
    deep: true
});

watch(
    headerFilterParams.value, () => {
        if (hasFilter.value) {
            let filterRenderTableRows = originTableRows.value.filter((t) => {
                return t.columns.reduce((res, item) => {
                    let filterValue = headerFilterParams.value[item.columnName];
                    return filterValue ? res && item.showValue === filterValue : res;
                }, true);
            });
            _resetRowSpan(filterRenderTableRows);
            renderTableRows.value = filterRenderTableRows;
        } else {
            _resetRowSpan(originTableRows.value);
            renderTableRows.value = originTableRows.value;
        }
    }, {
        deep: true,
    }
);
  
  /**
   * @desc:渲染函数
   */
function render() {
    originTableRows.value = createTable();
    renderTableRows.value = originTableRows.value;
}
  
/**
 * @desc 表格生成函数
 * @return 表格数据
 */
function createTable() {
    let tableData = [];
    let details = unref(Props.modelValue);
    for (let i = 0; i < skuTotal.value; i++) {
        let columns = specsValues.value.map((t, j) => {
            let { name, id } = getShowValue(i, j);
            return {
                shouldSetRowSpan: shouldSetRowSpan(i, j),
                showValue: name,
                valueId: id,
                columnName: t.name,
                columnId: t.id,
            };
        });
        //获取当前组合
        let pattern = columns
            .map((t) => t.valueId)
            .sort()
            .toString();
        //从详情中找回同一个组合的sku数据
        let rowDetails = details.find(
            (t) => [...t.sku_ids].sort().toString() === pattern
        );
        if (Props.keepWhenSpecChange) {
            rowDetails = rowDetails || details[i];
        }
        tableData.push({
            id: uuid(),
            ...createSkuPropertyFields(columns, i, unref(rowDetails)),
            columns,
        });
    }
    return tableData;
}
  
/**
 * @params rowIndex:行号 colIndex:列号
 * @return 要展示的规格内容
 */
function getShowValue(rowIndex, colIndex) {
    let values = specsValues.value[colIndex].values;
    let index;
    if (colIndex === specsValues.value.length - 1) {
        index = rowIndex % values.length;
    } else {
        let step = assignRule.value[colIndex];
        index = Math.floor(rowIndex / step);
        if (index >= values.length) {
            index = index % values.length;
        }
    }
    return values[index];
}
  
  /**
   * @params rowIndex:行号 colIndex:列号
   * @return 是否需要合并单元格
   */
  function shouldSetRowSpan(rowIndex, colIndex) {
    return rowIndex % assignRule.value[colIndex] === 0;
  }
  
/**
 * @params columns:所有列的数据，rowIndex:行号，row:行数据
 * @return sku属性列表
 * @desc 创建sku属性字段
*/
function createSkuPropertyFields(columns, rowIndex, row) {
    return propertiesValues.value.reduce((res, item) => {
      if (row) {
        res[item.id] = row[item.id] || "";
      } else {
        if (item.defaultValue) {
          // 设置默认值，可以为string或function，fuction时会传入行的索引和列的信息
          if (typeof item.defaultValue === "string") {
            res[item.id] = item.defaultValue;
          } else if (typeof item.defaultValue === "function") {
            res[item.id] = item.defaultValue({ rowIndex, columns });
          }
        } else {
          res[item.id] = "";
        }
      }
      return res;
    }, {});
}
  
  /**
   * @params table表格数据
   * @return void
   * @desc 重新判断单元格合并
   */
  function _resetRowSpan(table) {
    table.forEach((row, rowIndex) => {
      row.columns.forEach((column, columnIndex) => {
        column.shouldSetRowSpan = shouldSetRowSpan(rowIndex, columnIndex);
      });
    });
  }
  
  /**
   * @desc 删选事件触发
   */
  function onSltChange(value, name) {
    if (!value) {
      headerFilterParams.value[name] = null;
    }
  }
  
  /**
   * @params id:属性id
   * @desc 批量编辑
   */
  function onBulkEdit(id) {
    let value = skuPropertiesValue.value[id];
    renderTableRows.value.forEach((item) => {
      item[id] = value;
    });
    skuPropertiesValue.value[id] = "";
    getData();
  }
  
  /**
   * @params value:填入的属性值 ，columnInfo列数据，row行数据
   * @desc 检查属性值
   */
  function checkValue(value, columnInfo, row) {
    let { id, pattern } = columnInfo;
    if (pattern) {
      (row || skuPropertiesValue.value)[id] = value.replace(pattern, "");
    }
    getData();
  }
  
  /**
   * @desc 格式化输出的数据
   */
  function getData() {
    let data = originTableRows.value.map((t) => {
      let columnObj = propertiesValues.value.reduce((res, item) => {
        res[item.id] = item.format ? unref(item.format(t[item.id])) : t[item.id];
        return res;
      }, {});
      return {
        sku_ids: t.columns.map((t) => t.valueId),
        sku_names: t.columns.map((t) => t.showValue),
        ...columnObj,
      };
    });
    emit("update:modelValue", data);
  }
  </script>
  
  <style scoped>
  .sku-table {
    overflow: auto;
    position: relative;
    background-color: #f9f9f9;
    border: 1px solid #c6d1db;
    border-top: none;
  }
  .sku-table-header {
    background: #f5f7fa;
    overflow-x: hidden;
    position: relative;
  }
  .sku-table-header-cell {
    color: #333;
    font-weight: 400;
    height: 42px;
    margin-left: 1px;
    position: relative;
    font-size: 12px;
    border-top: 1px solid #c6d1db;
    text-overflow: ellipsis;
    word-break: break-all;
    padding: 6px;
  }
  .sku-table-header-cell + .sku-table-header-cell {
    border-left: none;
  }
  .sku-table-header-cell:first-child {
    border-left: none;
  }
  .sku-table-header-cell:last-child {
    border-right: none;
  }
  .sku-table-header-cell .spec-name {
    font-size: 14px;
    display: inline-block;
    min-width: 80px;
  }
  .sku-table-body {
    border-spacing: 0;
    border: 1px;
    border-color: #c6d1db;
    width: 100%;
  }
  .sku-table-body tr:first-of-type td {
    border-top: none !important;
  }
  .sku-table-body tr:last-of-type td {
    border-bottom: none !important;
  }
  .sku-table-body tr + tr .sku-table-body-cell {
    border-top: none;
  }
  .sku-table-body td:first-of-type {
    border-left-color: transparent;
  }
  .sku-table-body td:last-of-type {
    border-right: none;
  }
  .sku-table-body-cell {
    color: #323b44;
    font-size: 12px;
    text-overflow: ellipsis;
    word-break: break-all;
    text-align: left;
    background: #fff;
    vertical-align: middle;
    height: 32px;
    padding: 0 6px;
    min-width: 100px;
  }
  .sku-table-body-cell.hide {
    display: none;
  }
  .sku-table-body-cell.row-span-style {
    text-align: center;
    min-width: 100px;
  }
  .sku-table-body-cell + .sku-table-body-cell {
    border-left-color: transparent !important;
  }
  .sku-table-body-cell .el-input__inner {
    border: none !important;
    background-color: transparent;
  }
  .col-last-rowspan {
    border-bottom: none !important;
  }
  </style>
  <style>
  .no-border-input .el-input__inner {
    border-color: transparent;
    min-width: 100px;
  }
  .no-border-input .el-input__wrapper {
    &:hover,
    &:focus-visible {
      box-shadow: none;
      outline: none;
    }
    box-shadow: none;
  }
  </style>
  